package com.nami.gate.network.initializer;


import com.nami.gate.config.GateConfig;
import com.nami.gate.network.codec.v2.WsMessageDecoderV2;
import com.nami.gate.network.codec.v2.WsMessageEncoderV2;
import com.nami.gate.network.handler.HeartBeatHandler;
import com.nami.gate.network.handler.NettyServerHandler;
import com.nami.gate.process.upmsg.PackageProcessFactory;
import com.nami.gate.middleware.mq.MqSender;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;

import javax.net.ssl.SSLEngine;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

/**
 * @author
 */
public class WsServerInitializer extends ChannelInitializer<SocketChannel> {

    private GateConfig gateConfig;

    private MqSender mqSender;

    private PackageProcessFactory factory;

    public WsServerInitializer(GateConfig gateConfig, MqSender mqSender, PackageProcessFactory factory) {
        this.gateConfig = gateConfig;
        this.mqSender = mqSender;
        this.factory = factory;
    }

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        if (gateConfig.isSslEnable()) {
            pipeline.addFirst("ssl", new SslHandler(buildSslEngine(socketChannel)));
        }
        // 日志
        pipeline.addLast("netty-log", new LoggingHandler(LogLevel.DEBUG));
        // websocket 基于http协议，所以要有http编解码器
        pipeline.addLast("http-codec", new HttpServerCodec());
        // 对写大数据流的支持
        pipeline.addLast("http-chunked", new ChunkedWriteHandler());
        // 几乎在netty中的编程，都会使用到此hanler
        pipeline.addLast("aggregator", new HttpObjectAggregator(65535));
        /**
         * websocket 服务器处理的协议，用于指定给客户端连接访问的路由 : /ws
         * 本handler会帮你处理一些繁重的复杂的事
         * 会帮你处理握手动作： handshaking（close, ping, pong） ping + pong = 心跳
         * 对于websocket来讲，都是以frames进行传输的，不同的数据类型对应的frames也不同
         */
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));

        pipeline.addLast("encoder", new WsMessageEncoderV2());
        pipeline.addLast("decoder", new WsMessageDecoderV2());

        pipeline.addLast(new IdleStateHandler(30, 30, 10, TimeUnit.SECONDS));
        pipeline.addLast(new HeartBeatHandler(gateConfig.getHeartBeatInterval(), mqSender));
        pipeline.addLast(new NettyServerHandler(mqSender, gateConfig.getRpcConfig(), factory));
    }

    private SSLEngine buildSslEngine(SocketChannel socketChannel) throws IOException {
        InputStream is = null;
        SslContext sslContext = SslContextBuilder.forServer(is
            , is).build();
        SSLEngine sslEngine = sslContext.newEngine(socketChannel.alloc());
        // 服务器端模式，客户端模式设置为true
        sslEngine.setUseClientMode(false);
        // 不需要验证客户端，客户端不设置该项；  SSL/TLS 开启后有多种认证方式：1-不需要认证，2-单向认证（一般是客户端认证），3-双向认证
        sslEngine.setNeedClientAuth(false);
        return sslEngine;
    }

}
